<!--
// Copyright © 2020 Anticrm Platform Contributors.
// Copyright © 2021, 2022, 2023, 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
  import { IconSize } from '@hcengineering/ui'
  import { Editor } from '@tiptap/core'
  import textEditor, {
    type TextEditorAction,
    type ActionContext,
    type TextEditorActionKind
  } from '@hcengineering/text-editor'
  import { createQuery } from '@hcengineering/presentation'
  import { getResource } from '@hcengineering/platform'

  import { inlineToolbarKey } from './extension/inlineToolbar'
  import TextActionButton from './TextActionButton.svelte'

  export let formatButtonSize: IconSize = 'small'
  export let editor: Editor
  export let toolbar: HTMLElement | null
  export let visible: boolean = true
  export let kind: TextEditorActionKind = 'text'

  const actionsQuery = createQuery()

  $: actionCtx = editor?.extensionManager.extensions.find((ext) => ext.name === inlineToolbarKey)?.options.ctx

  let actions: TextEditorAction[]
  $: actionsQuery.query(textEditor.class.TextEditorAction, {}, (result) => {
    actions = result.filter((action) => action.kind === kind || (kind === 'text' && action.kind === undefined))
  })

  let visibleActions: TextEditorAction[]
  $: void getVisibleActions(editor, actions, actionCtx)

  async function getVisibleActions (
    e: Editor | undefined,
    actions: TextEditorAction[],
    ctx: ActionContext
  ): Promise<void> {
    const newVisibleActions = []
    if (e !== undefined && actions !== undefined) {
      for (const action of actions) {
        const tester = action.visibilityTester

        if (typeof action.action !== 'string') {
          const { command } = action.action

          if ((editor.commands as any)[command] === undefined) {
            console.error(`Command ${command} not found`)
            continue
          }
        }

        if (tester === undefined) {
          newVisibleActions.push(action)
          continue
        }

        const testerFunc = await getResource(tester)
        if (await testerFunc(e, ctx)) {
          newVisibleActions.push(action)
        }
      }
    }

    visibleActions = newVisibleActions
  }

  $: categories = visibleActions.reduce<[number, TextEditorAction][][]>((acc, action) => {
    const { category, index } = action

    if (acc[category] === undefined) {
      acc[category] = []
    }

    acc[category].push([index, action])

    return acc
  }, [])
  $: categories.forEach((category) => {
    category.sort((a, b) => a[0] - b[0])
  })
</script>

<div bind:this={toolbar} style="visibility: hidden;">
  {#if editor && visible && visibleActions.length > 0}
    <div class="text-editor-toolbar buttons-group xsmall-gap mb-4">
      {#each Object.values(categories) as category, index}
        {#if index > 0}
          <div class="buttons-divider" />
        {/if}

        {#each category as [_, action]}
          <TextActionButton {action} {editor} size={formatButtonSize} {actionCtx} on:focus />
        {/each}
      {/each}
    </div>
  {/if}
</div>

<style lang="scss">
  .text-editor-toolbar {
    margin: -0.5rem -0.25rem 0.5rem;
    padding: 0.375rem;
    background-color: var(--theme-comp-header-color);
    border-radius: 0.5rem;
    box-shadow: var(--button-shadow);
    z-index: 1;
  }
</style>
